Skip to content

MNE-Python compatibility layer (epic #139) - #191

Merged
neuromechanist merged 5 commits into
mainfrom
feature/issue-139-epic-mne-compat
Jul 18, 2026
Merged

MNE-Python compatibility layer (epic #139)#191
neuromechanist merged 5 commits into
mainfrom
feature/issue-139-epic-mne-compat

Conversation

@neuromechanist

Copy link
Copy Markdown
Member

Summary

Adds an MNE-Python compatibility layer for pamica, additive throughout: the scikit-learn-style AMICA API and the byte-identical EEGLAB I/O are unchanged. MNE-Python users get a native entry point via from pamica.mne_compat import AMICAICA, shipped as the optional pamica[mne] extra so import pamica never requires MNE. Works with current MNE, no fork or extension.

Closes #139.

Phases

Design notes

  • MNE has no multi-model concept, so multi-model AMICA is exposed per-model plus a dominance accessor, not forced into MNE's single-unmixing ICA.
  • The per-model export folds each model's data-space center c into pca_mean_; single-model (c=0) stays byte-identical.
  • pca_components_ is kept orthonormal (sphere written as V diag(1/sqrt(e)) V^T) so MNE's scalp maps come out in channel space.
  • PCA reduction (pcakeep/pcadb) is rejected (the export assumes full-rank whitening); non-finite input and degenerate fits are refused.

Test plan

  • New pamica/tests/mne_tests/ (46 tests) run on the real bundled eeglab_data.set via a dedicated test-mne CI job (uv sync --extra mne); the base job skips them via importorskip. New backend suites (test_ng_model_posterior.py, test_ng_metadata.py) run in base CI. No mocks.
  • Every phase went through a 4-5 reviewer Sonnet pass; all findings addressed (see the per-phase PRs Phase 1: core MNE wrapper (single-model) #187-Phase 4: expose PMI/MIR through the MNE wrapper #190). CI green on all four.

Merge

Per the repo policy, an epic PR uses a regular merge (not squash) to preserve the per-phase history.

* Add AMICAICA MNE wrapper (single-model)

* Add MNE wrapper tests and CI job

* Document AMICAICA MNE wrapper

* Harden AMICAICA: atomic fit, guards, degenerate refusal

* Test eigen-order, guards, save-reload, refit safety

* Document plot_sources, PCA-reduction limit, guards

* Fix typo flagged by typos CI
* Add public model_loglik/model_probability accessors

* Let plot_model_probability accept a live lht array

* Expose multi-model AMICA through AMICAICA

* Document multi-model MNE wrapper

* Guard scoring path: finiteness, underflow, docstrings

* Harden AMICAICA multi-model: kw-only model_idx, guards, tests

* Fix stale Notes mapping doc; add viz/docs coverage
)

* Add pdftype/rho/shared-components metadata accessors

* Expose fitted metadata through AMICAICA

* Document metadata accessors

* Validate model_idx and guard get_rho non-finite
* Expose MIR/PMI metrics through AMICAICA

* Test MNE-wrapper MIR/PMI accessors

* Document MIR/PMI accessors

* Pin pmi-on-epochs, nbins, degenerate guard for metrics
@neuromechanist

Copy link
Copy Markdown
Member Author

Integrated review (Sonnet, cross-phase)

Ran a focused review over the combined 4-phase diff for integration/coherence issues (beyond the per-phase reviews on #187-#190). The layering checked out: guard ordering (_check_fitted before _check_model_idx) is uniform across all 13 call sites; the two same-named _check_model_idx validators (wrapper + backend, added in different phases) produce identical errors and bound against the same value (redundant defense-in-depth, not a double-validation bug); the phase-3 backend _check_model_idx retrofit breaks no existing caller; the viz.plot_model_probability dual out/lht API is only ever called with lht= from the wrapper; packaging (tool.setuptools.packages), the test-mne CI job + coverage omit, and the docs/changelog are all complete across the four phases.

Two findings:

  • Module docstring was stale (labeled "phase 1", omitted phases 3-4). Fixed in the follow-up commit — it now covers the metadata accessors and mir/pmi.
  • to_mne_ica's model_idx is not keyword-only unlike the other model-scoped methods. Kept as positional-or-keyword by design: the keyword-only convention on get_sources/apply/plot_components/etc. exists specifically to protect their *args/**kwargs passthrough to MNE from a positional collision. to_mne_ica takes only model_idx (no passthrough, no collision), so to_mne_ica(h) is the natural call and is what the internal delegators and tests use; forcing keyword-only would break those for no safety benefit.

CI re-running after the docstring commit.

@neuromechanist
neuromechanist merged commit 3be06c8 into main Jul 18, 2026
7 checks passed
@neuromechanist
neuromechanist deleted the feature/issue-139-epic-mne-compat branch July 18, 2026 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Epic: MNE-Python compatibility layer (additive, EEGLAB I/O unchanged)

1 participant